package untils

import (
	"context"
	"encoding/json"
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"log"
	"math"
	"smart-health-platforms/config"
	"sort"
	"strings"
	"sync"
	"time"
)

var (
	Config     Configs         // 系统配置
	dataCache  []RawHealthData // 原始数据缓存（最多存10条）
	cacheMutex sync.Mutex      // 缓存锁（保证并发安全）
)

// Config 系统配置参数结构体
type Configs struct {
	MongoDBName      string        // 数据库名
	MongoColl        string        // 集合名
	ReceiveInterval  time.Duration // 数据接收间隔（分钟）
	CleanInterval    time.Duration // 数据清洗间隔（分钟）
	BatchSize        int           // 每批处理的数据量（固定10条）
	MissingThreshold int           // 缺失数据阈值（超过此值需重采）
}

// RawHealthData 原始健康数据结构体（设备上报的原始格式）
type RawHealthData struct {
	DeviceID    string   `json:"device_id"`   // 设备唯一标识
	UserID      string   `json:"user_id"`     // 关联用户ID
	Timestamp   int64    `json:"timestamp"`   // 采集时间戳（毫秒）
	Temperature *float64 `json:"temperature"` // 体温（指针类型：nil表示缺失）
	HeartRate   *float64 `json:"heart_rate"`  // 心率（指针类型：nil表示缺失）
	Systolic    *float64 `json:"systolic"`    // 收缩压（指针类型：nil表示缺失）
	Diastolic   *float64 `json:"diastolic"`   // 舒张压（指针类型：nil表示缺失）
	Unit        string   `json:"unit"`        // 单位体系（metric/imperial）
}

// CleanedHealthData 清洗后的数据结构体（存储到MongoDB的格式）
type CleanedHealthData struct {
	DeviceID     string    `bson:"device_id"`     // 设备ID
	UserID       string    `bson:"user_id"`       // 用户ID
	Timestamp    time.Time `bson:"timestamp"`     // 标准化时间（time.Time类型）
	Temperature  float64   `bson:"temperature"`   // 清洗后体温
	HeartRate    float64   `bson:"heart_rate"`    // 清洗后心率
	Systolic     float64   `bson:"systolic"`      // 清洗后收缩压
	Diastolic    float64   `bson:"diastolic"`     // 清洗后舒张压
	Cleaned      bool      `bson:"cleaned"`       // 是否已清洗
	CleanTime    time.Time `bson:"clean_time"`    // 清洗时间
	Abnormal     bool      `bson:"abnormal"`      // 是否存在异常
	AbnormalInfo string    `bson:"abnormal_info"` // 异常详情（含缺失填充记录）
	Status       string    `bson:"status"`        // 处理状态（success/need_recollect）
}

// 全局变量（核心资源与缓存）

// initConfig 初始化系统配置参数
func InitConfig() {
	Config = Configs{
		MongoDBName:      "health_db",
		MongoColl:        "health_data",
		ReceiveInterval:  1 * time.Minute,  // 每分钟接收1条
		CleanInterval:    10 * time.Minute, // 每10分钟清洗一次
		BatchSize:        10,               // 每批处理10条
		MissingThreshold: 5,                // 缺失超5条需重采
	}
}

// -------------------------- 体温清洗模块 --------------------------
// processTemperature 处理体温数据的完整流程
// 返回值：中位数、缺失索引、单条清洗函数、错误信息
func ProcessTemperature(rawList []RawHealthData) (
	median float64,
	missingIndices []int,
	cleanFunc func(*RawHealthData, int) (float64, string),
	err error,
) {
	// 1. 统计有效数据和缺失索引
	var validValues []float64
	for i, raw := range rawList {
		// 判定缺失：字段为nil或无效值（<=0或NaN）
		if raw.Temperature == nil || math.IsNaN(*raw.Temperature) || *raw.Temperature <= 0 {
			missingIndices = append(missingIndices, i)
		} else {
			validValues = append(validValues, *raw.Temperature)
		}
	}

	// 2. 校验缺失是否超阈值
	if len(missingIndices) > Config.MissingThreshold {
		return 0, nil, nil, fmt.Errorf("体温缺失过多（%d条），请重采", len(missingIndices))
	}

	// 3. 计算有效数据的中位数（用于填充缺失值）
	median = calculateMedian(validValues)

	// 4. 定义单条数据清洗函数（闭包：复用median和missingIndices）
	cleanFunc = func(raw *RawHealthData, index int) (float64, string) {
		var abnormalInfo string
		isMissing := isInSlice(index, missingIndices)

		if isMissing {
			// 缺失值用中位数填充
			abnormalInfo = fmt.Sprintf("体温缺失，用中位数%.1f℃填充", median)
			return median, abnormalInfo
		}

		// 单位转换：英制（华氏度）→公制（摄氏度）
		cleanedVal := *raw.Temperature
		if raw.Unit == "imperial" {
			cleanedVal = (cleanedVal - 32) * 5 / 9 // 华氏转摄氏公式
		}

		// 范围校验（正常体温：35-42℃）
		if cleanedVal < 35 || cleanedVal > 42 {
			abnormalInfo = fmt.Sprintf("体温异常: %.1f℃（正常35-42℃）", cleanedVal)
		}

		return cleanedVal, abnormalInfo
	}
	return median, missingIndices, cleanFunc, nil
}

// -------------------------- 心率清洗模块 --------------------------
// processHeartRate 处理心率数据的完整流程
func ProcessHeartRate(rawList []RawHealthData) (
	median float64,
	missingIndices []int,
	cleanFunc func(*RawHealthData, int) (float64, string),
	err error,
) {
	// 1. 统计有效数据和缺失索引
	var validValues []float64
	for i, raw := range rawList {
		if raw.HeartRate == nil || math.IsNaN(*raw.HeartRate) || *raw.HeartRate <= 0 {
			missingIndices = append(missingIndices, i)
		} else {
			validValues = append(validValues, *raw.HeartRate)
		}
	}
	// 2. 校验缺失是否超阈值
	if len(missingIndices) > Config.MissingThreshold {
		return 0, nil, nil, fmt.Errorf("心率缺失过多（%d条），请重采", len(missingIndices))
	}
	// 3. 计算中位数
	median = calculateMedian(validValues)
	// 4. 定义单条清洗函数
	cleanFunc = func(raw *RawHealthData, index int) (float64, string) {
		var abnormalInfo string
		isMissing := isInSlice(index, missingIndices)

		if isMissing {
			abnormalInfo = fmt.Sprintf("心率缺失，用中位数%.0f次/分填充", median)
			return median, abnormalInfo
		}
		// 心率无需单位转换
		cleanedVal := *raw.HeartRate
		// 范围校验（正常心率：30-220次/分）
		if cleanedVal < 30 || cleanedVal > 220 {
			abnormalInfo = fmt.Sprintf("心率异常: %.0f次/分（正常30-220次/分）", cleanedVal)
		}
		return cleanedVal, abnormalInfo
	}
	return median, missingIndices, cleanFunc, nil
}

// -------------------------- 血压清洗模块 --------------------------
// processBloodPressure 处理血压数据的完整流程（收缩压+舒张压联合处理）
func ProcessBloodPressure(rawList []RawHealthData) (
	medianSystolic, medianDiastolic float64,
	missingSystolic, missingDiastolic []int,
	cleanFunc func(*RawHealthData, int) (float64, float64, string),
	err error,
) {
	// 1. 分别统计收缩压和舒张压的有效数据与缺失索引
	var validSystolic, validDiastolic []float64
	for i, raw := range rawList {
		// 收缩压处理
		if raw.Systolic == nil || math.IsNaN(*raw.Systolic) || *raw.Systolic <= 0 {
			missingSystolic = append(missingSystolic, i)
		} else {
			validSystolic = append(validSystolic, *raw.Systolic)
		}
		// 舒张压处理
		if raw.Diastolic == nil || math.IsNaN(*raw.Diastolic) || *raw.Diastolic <= 0 {
			missingDiastolic = append(missingDiastolic, i)
		} else {
			validDiastolic = append(validDiastolic, *raw.Diastolic)
		}
	}
	// 2. 校验收缩压/舒张压缺失是否超阈值
	if len(missingSystolic) > Config.MissingThreshold {
		return 0, 0, nil, nil, nil, fmt.Errorf("收缩压缺失过多（%d条），请重采", len(missingSystolic))
	}
	if len(missingDiastolic) > Config.MissingThreshold {
		return 0, 0, nil, nil, nil, fmt.Errorf("舒张压缺失过多（%d条），请重采", len(missingDiastolic))
	}
	// 3. 计算两者的中位数
	medianSystolic = calculateMedian(validSystolic)
	medianDiastolic = calculateMedian(validDiastolic)
	// 4. 定义单条清洗函数（含收缩压与舒张压的逻辑校验）
	cleanFunc = func(raw *RawHealthData, index int) (systolic, diastolic float64, abnormalInfo string) {
		var infos []string
		isSystolicMissing := isInSlice(index, missingSystolic)
		isDiastolicMissing := isInSlice(index, missingDiastolic)
		// 收缩压处理
		if isSystolicMissing {
			systolic = medianSystolic
			infos = append(infos, fmt.Sprintf("收缩压缺失，用中位数%.0fmmHg填充", medianSystolic))
		} else {
			systolic = *raw.Systolic
			if raw.Unit == "imperial" {
				systolic *= 7.5 // kPa转mmHg（1kPa≈7.5mmHg）
			}
			// 范围校验（正常收缩压：70-200mmHg）
			if systolic < 70 || systolic > 200 {
				infos = append(infos, fmt.Sprintf("收缩压异常: %.0fmmHg（正常70-200mmHg）", systolic))
			}
		}
		// 舒张压处理
		if isDiastolicMissing {
			diastolic = medianDiastolic
			infos = append(infos, fmt.Sprintf("舒张压缺失，用中位数%.0fmmHg填充", medianDiastolic))
		} else {
			diastolic = *raw.Diastolic
			if raw.Unit == "imperial" {
				diastolic *= 7.5 // kPa转mmHg
			}
			// 范围校验（正常舒张压：40-120mmHg）
			if diastolic < 40 || diastolic > 120 {
				infos = append(infos, fmt.Sprintf("舒张压异常: %.0fmmHg（正常40-120mmHg）", diastolic))
			}
		}
		// 逻辑校验：收缩压必须≥舒张压
		if systolic < diastolic {
			infos = append(infos, fmt.Sprintf("血压逻辑异常: 收缩压(%.0f) < 舒张压(%.0f)", systolic, diastolic))
		}
		// 合并异常信息
		if len(infos) > 0 {
			abnormalInfo = strings.Join(infos, "; ")
		}
		return systolic, diastolic, abnormalInfo
	}
	return medianSystolic, medianDiastolic, missingSystolic, missingDiastolic, cleanFunc, nil
}

// -------------------------- 批量清洗入口 --------------------------
// cleanBatchData 批量清洗10条原始数据，返回清洗后的数据列表
func CleanBatchData(rawList []RawHealthData) ([]CleanedHealthData, error) {
	// 校验数据量是否为10条
	if len(rawList) != Config.BatchSize {
		return nil, fmt.Errorf("数据量异常（预期%d条，实际%d条）", Config.BatchSize, len(rawList))
	}
	// 1. 调用各指标清洗模块，获取单条清洗函数
	_, _, tempCleanFunc, err := ProcessTemperature(rawList)
	if err != nil {
		return nil, err
	}
	_, _, hrCleanFunc, err := ProcessHeartRate(rawList)
	if err != nil {
		return nil, err
	}
	_, _, _, _, bpCleanFunc, err := ProcessBloodPressure(rawList)
	if err != nil {
		return nil, err
	}
	// 2. 逐条清洗数据
	var cleanedList []CleanedHealthData
	for i, raw := range rawList {
		// 调用体温清洗函数
		tempVal, tempInfo := tempCleanFunc(&raw, i)
		// 调用心率清洗函数
		hrVal, hrInfo := hrCleanFunc(&raw, i)
		// 调用血压清洗函数
		systolicVal, diastolicVal, bpInfo := bpCleanFunc(&raw, i)
		// 合并所有异常信息
		var allInfos []string
		if tempInfo != "" {
			allInfos = append(allInfos, tempInfo)
		}
		if hrInfo != "" {
			allInfos = append(allInfos, hrInfo)
		}
		if bpInfo != "" {
			allInfos = append(allInfos, bpInfo)
		}
		// 构造清洗后的数据
		cleaned := CleanedHealthData{
			DeviceID:     raw.DeviceID,
			UserID:       raw.UserID,
			Timestamp:    time.UnixMilli(raw.Timestamp), // 时间戳转time.Time
			Temperature:  tempVal,
			HeartRate:    hrVal,
			Systolic:     systolicVal,
			Diastolic:    diastolicVal,
			Cleaned:      true,
			CleanTime:    time.Now(),
			Abnormal:     len(allInfos) > 0, // 有异常信息则标记为异常
			AbnormalInfo: strings.Join(allInfos, "; "),
			Status:       "success",
		}
		cleanedList = append(cleanedList, cleaned)
	}
	if err := StoreBatchData(cleanedList); err != nil {
		log.Printf("存储清洗后数据失败: %v", err)
		return nil, err
	}
	return cleanedList, nil
}

// -------------------------- 工具函数 --------------------------
// calculateMedian 计算切片的中位数（用于填充缺失值）
func calculateMedian(nums []float64) float64 {
	if len(nums) == 0 {
		return 0 // 理论上不会触发（因缺失≤5时有效数据≥5）
	}
	sort.Float64s(nums) // 排序
	n := len(nums)
	if n%2 == 1 {
		return nums[n/2] // 奇数：取中间值
	}
	return (nums[n/2-1] + nums[n/2]) / 2 // 偶数：取中间两值的平均
}

// isInSlice 判断索引是否在缺失列表中（用于判定是否需要填充）
func isInSlice(idx int, list []int) bool {
	for _, i := range list {
		if idx == i {
			return true
		}
	}
	return false
}

// messageHandler MQTT消息处理函数：解析数据并缓存
var MessageHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	log.Printf("收到MQTT消息: 主题=%s, 负载=%s", msg.Topic(), msg.Payload())

	// 解析JSON数据
	var rawData RawHealthData
	if err := json.Unmarshal(msg.Payload(), &rawData); err != nil {
		log.Printf("解析JSON失败: %v", err)
		return
	}

	// 加锁缓存数据（最多保留10条，超过则保留最新的）
	cacheMutex.Lock()
	dataCache = append(dataCache, rawData)
	if len(dataCache) > Config.BatchSize {
		dataCache = dataCache[len(dataCache)-Config.BatchSize:] // 截断旧数据
	}
	cacheMutex.Unlock()

	log.Printf("数据已缓存（当前缓存量: %d条）", len(dataCache))
}

// startCleanTask 启动定时清洗任务（每10分钟执行一次）
func StartCleanTask() {
	ticker := time.NewTicker(Config.CleanInterval)
	defer ticker.Stop()
	log.Printf("定时清洗任务启动（每%s执行一次）", Config.CleanInterval)

	for range ticker.C {
		log.Println("开始执行清洗任务...")
		cacheMutex.Lock()
		// 缓存不足10条则等待下一轮
		if len(dataCache) < Config.BatchSize {
			cacheMutex.Unlock()
			log.Printf("缓存不足%d条（当前%d条），等待下一轮", Config.BatchSize, len(dataCache))
			continue
		}
		// 取出缓存数据并清空
		batchData := dataCache
		dataCache = []RawHealthData{}
		cacheMutex.Unlock()
		// 批量清洗
		cleanedList, err := CleanBatchData(batchData)
		if err != nil {
			log.Printf("清洗失败: %v", err)
			continue
		}
		// 存储清洗后的数据
		if err := StoreBatchData(cleanedList); err != nil {
			log.Printf("存储失败: %v", err)
		} else {
			log.Printf("成功存储%d条清洗后的数据", len(cleanedList))
		}
	}
}

// storeBatchData 批量存储清洗后的数据到MongoDB
func StoreBatchData(cleanedList []CleanedHealthData) error {
	if len(cleanedList) == 0 {
		return nil
	}

	// 转换为MongoDB文档格式
	docs := make([]interface{}, len(cleanedList))
	for i, item := range cleanedList {
		docs[i] = map[string]interface{}{
			"device_id":     item.DeviceID,
			"user_id":       item.UserID,
			"timestamp":     item.Timestamp,
			"temperature":   item.Temperature,
			"heart_rate":    item.HeartRate,
			"systolic":      item.Systolic,
			"diastolic":     item.Diastolic,
			"cleaned":       item.Cleaned,
			"clean_time":    item.CleanTime,
			"abnormal":      item.Abnormal,
			"abnormal_info": item.AbnormalInfo,
			"status":        item.Status,
			"created_at":    time.Now(),
		}
	}

	// 批量插入
	_, err := config.CleanedCollection.InsertMany(context.Background(), docs)
	if err != nil {
		return fmt.Errorf("批量插入清洗后数据失败: %v", err)
	}

	return nil
}
